using System;
using Base;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Base;
namespace Entities
{
    public class ProjectileController : IProjectileController
    {
        public List<Projectile> projectiles = new List<Projectile>();
        public List<Projectile> deadProjectiles = new List<Projectile>();
        public List<Projectile> newDeadProjectiles = new List<Projectile>();
        IParticleController particleController;

        public ProjectileController(IParticleController particles)
        {
            particleController = particles;
        }

        public void Add(Vector3 direction, Vector3 position, float speed, long lifetime, IActor target, bool homing)
        {
            Projectile newProjectile;
            if (deadProjectiles.Count == 0)
            {
                newProjectile = new Projectile();
            }
            else
            {
                newProjectile = deadProjectiles[0];
                deadProjectiles.RemoveAt(0);
            }

            newProjectile.Position = position;
            newProjectile.Direction = direction;
            newProjectile.Speed = speed;
            newProjectile.Lifetime = lifetime;
            newProjectile.Birth = DateTime.Now.Ticks;
            newProjectile.Homing = homing;
            newProjectile.Target = target;
            projectiles.Add(newProjectile);
            if (newProjectile.Homing)
            {
                particleController.CreateTrailEmitter(newProjectile.Key, 200, newProjectile.Position);
            }

        }

        public void Update(GameTime gameTime, IDrawing3DManager drawing)
        {
            foreach (Projectile currentProjectile in projectiles)
            {
                if (DateTime.Now.Ticks - currentProjectile.Birth >= currentProjectile.Lifetime)
                {
                    deadProjectiles.Add(currentProjectile);
                    newDeadProjectiles.Add(currentProjectile);
                    if (currentProjectile.Homing)
                    {
                        particleController.DeleteTrailEmitter(currentProjectile.Key);
                    }
                }
                else
                {
                    UpdatePosition(currentProjectile);
                    if (currentProjectile.Homing)
                    {
                        particleController.UpdateTrailEmitter(currentProjectile.Key, gameTime, currentProjectile.Position);
                    }
                    else
                    {
                        drawing.AddLine(currentProjectile.Position, currentProjectile.Position += currentProjectile.Direction * 0.6f, Color.Red, false);
                    }
                    if (CheckDistance(currentProjectile))
                    {
                        deadProjectiles.Add(currentProjectile);
                        newDeadProjectiles.Add(currentProjectile);
                        if (currentProjectile.Homing)
                        {
                            particleController.DeleteTrailEmitter(currentProjectile.Key);
                            particleController.CreateExplosion(currentProjectile.Position);
                        }
                    }
                }
            }
            foreach (Projectile currentProjectile in newDeadProjectiles)
            {
                projectiles.Remove(currentProjectile);
            }
            newDeadProjectiles.Clear();
            GameInformation.ProjectileCount = projectiles.Count + deadProjectiles.Count;
        }

        private void UpdatePosition(Projectile currentProjectile)
        {
            if (currentProjectile.Homing)
            {
                Vector3 newDirection = currentProjectile.Target.AdjustedPosition - currentProjectile.Position;
                
                newDirection.Normalize();

                currentProjectile.Direction = newDirection;
                currentProjectile.Position += currentProjectile.Direction * currentProjectile.Speed;
            }
            else
            {
                currentProjectile.Position += currentProjectile.Direction * currentProjectile.Speed;
            }
        }
        float minDifference = 50.0f;
        private bool CheckDistance(Projectile currentProjectile)
        {
            Vector3 difference = currentProjectile.Target.AdjustedPosition - currentProjectile.Position;
            if (difference.Length() < minDifference)
            {
                minDifference = difference.Length();
            }
            if (difference.Length() <= 2.5f)
            {
                currentProjectile.Target.Hit(1.0f);
                return true;
            }
            return false;
        }

    }

    public class Projectile
    {
        private Vector3 direction;
        private Vector3 position;
        private float speed;
        private long lifetime;
        private long birth;
        private bool alive = true;
        private bool homing = false;
        private string key = Guid.NewGuid().ToString();
        private IActor target;

        public Vector3 Direction
        {
            get { return direction; }
            set { direction = value; }
        }

        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        public float Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public long Lifetime
        {
            get { return lifetime; }
            set { lifetime = value; }
        }

        public long Birth
        {
            get { return birth; }
            set { birth = value; }
        }

        public bool Alive
        {
            get { return alive; }
            set { alive = value; }
        }

        public bool Homing
        {
            get { return homing; }
            set { homing = value; }
        }

        public string Key
        {
            get { return key; }
            set { key = value; }
        }

        public IActor Target
        {
            get { return target; }
            set { target = value; }
        }
    }
}
